include REXML
require 'net/http'
require 'net/https'
require 'uri'

class Ups
  attr_reader :name, :rates, :response_code, :error
  
  def initialize(zip_to, weight, options = {})
    @zip_to = zip_to
    @weight = weight
    @service = options[:service_code]
    
    yaml = YAML.load(File.new("#{RAILS_ROOT}/config/shipping_rate.yml"))
    
    shipper_config = yaml['shipper']
    @zip_from = shipper_config['postal_code']
    @country_code = shipper_config['country_code']
    
    ups_config = yaml['ups'][ENV['RAILS_ENV']]
    @name = ups_config['name']
    @uri = ups_config['uri']
    @access_key = ups_config['access_key']
    @user_id = ups_config['user_id']
    @password = ups_config['password']

    @rates = get_rates
  end
  
  def to_xml
    xml = ""
    xml << access_request_xml
    xml << rss_request_xml
    return xml
  end
  
  private
  def get_rates
    rates = []
    xml = to_xml
    uri = URI.parse(@uri)
    http = Net::HTTP.new(uri.host, 443)
    http.use_ssl = true 
    response = http.request_post(uri.path, xml, {'Content-Type' => 'text/xml; charset=utf-8'})
    # Read the response
    response_xml = Document.new(response.body)
    response_status = response_xml.elements["RatingServiceSelectionResponse/Response"]
    response_code = response_status.elements["ResponseStatusCode"].text
    if response_code == "1"
       response_xml.elements.each("RatingServiceSelectionResponse/RatedShipment") do |rate|
         rates << {
             :service_code => "Ups_#{rate.elements["Service/Code"].text}_#{rate.elements["TotalCharges/MonetaryValue"].text}",
             :service_description => get_service_name_from_code(rate.elements["Service/Code"].text),
             :charge => rate.elements["TotalCharges/MonetaryValue"].text,
             :currency_code => rate.elements["TotalCharges/CurrencyCode"].text
         }
       end
       return rates
    else
      @error = response_status.elements["Error/ErrorDescription"].text
      return nil
    end
  end
  
  def get_service_name_from_code(code)
    codes = {}
    # Get the codes for the correct country
    case @country_code
      when 'US'
        codes = {
          "01" => "UPS Next Day Air",
          "02" => "UPS Second Day Air",
          "03" => "UPS Ground",
          "07" => "UPS Worldwide Express",
          "08" => "UPS Worldwide Expedited",
          "11" => "UPS Standard",
          "12" => "UPS Three-Day Select",
          "13" => "UPS Next Day Air Saver",
          "14" => "UPS Next Day Air Early A.M.",
          "54" => "UPS Worldwide Express Plus",
          "59" => "UPS Second Day Air A.M. ",
          "65" => "UPS Saver"
        }
      when 'PR'
        codes = {
          "01" => "UPS Next Day Air",
          "02" => "UPS Second Day Air",
          "03" => "UPS Ground",
          "07" => "UPS Worldwide Express",
          "08" => "UPS Worldwide Expedited",
          "14" => "UPS Next Day Air® Early A.M.",
          "54" => "UPS Worldwide Express Plus",
          "65" => "UPS Saver"
        }
      when 'CA'
        codes = {
          "01" => "UPS Express",
          "02" => "UPS Expedited",
          "07" => "UPS Worldwide Express",
          "08" => "UPS Worldwide Expedited",
          "11" => "UPS Standard",
          "12" => "UPS Three-Day Select",
          "14" => "UPS Express Early A.M.",
          "65" => "UPS Saver"
        }
      when 'MX'
        codes = {
          "07" => "UPS Express",
          "08" => "UPS Expedited",
          "54" => "UPS Express Plus",
          "65" => "UPS Saver"
        }
        
      #when 'AT','BE','BG','CY','CZ','DK',
      #  'EE','FI','FR','DE','GR','HU',
      #  'IE','IT', 'LV','LT','LU','MT',
      #  'NL','PL','PT','RO','SK','SI',
      #  'ES','SE','GB'
        
    end
    
    if codes[code]
      return codes[code]
    else
      return "UPS Service name not available"
    end
    
  end
  
  def access_request_xml
    doc = REXML::Document.new
    access_request = Element.new "AccessRequest"
    access_licence_number = access_request.add_element "AccessLicenseNumber"
    access_licence_number.text = @access_key
    user_id = access_request.add_element "UserId"
    user_id.text = @user_id
    password = access_request.add_element "Password"
    password.text = @password
    doc << access_request
    doc << REXML::XMLDecl.new
    return doc.to_s
  end
  
  def rss_request_xml
    # Rating Service Selection Request
    doc = REXML::Document.new
    rss_request = REXML::Element.new "RatingServiceSelectionRequest"
    
    request = rss_request.add_element "Request"
    request_action = request.add_element "RequestAction"
    request_action.text = "rate"
    request_option = request.add_element "RequestOption"
    request_option.text = (@service.nil?) ? "Shop" : "Rate"
    
    pickup_type = rss_request.add_element "PickupType"
    pickup_type_code = pickup_type.add_element "Code"
    pickup_type_code.text = "01"
    
    shipment = rss_request.add_element "Shipment"
    
    if !@service.nil?
      service = shipment.add_element "Service" 
      service_code = service.add_element "Code"
      service_code.text = @service.to_s
    end
    
    shipper = shipment.add_element "Shipper"
    shipper_address = shipper.add_element "Address"
    shipper_postal_code = shipper_address.add_element "PostalCode"
    shipper_postal_code.text = @zip_from

    ship_to = shipment.add_element "ShipTo"
    address = ship_to.add_element "Address"
    postal_code = address.add_element "PostalCode"
    postal_code.text = @zip_to
    
    package = shipment.add_element "Package"
    packaging_type = package.add_element "PackagingType"
    packaging_type_code = packaging_type.add_element "Code"
    packaging_type_code.text = "00"
    package_weight = package.add_element "PackageWeight"
    unit_of_measure = package_weight.add_element "UnitOfMeasurement"
    code = unit_of_measure.add_element "Code"
    code.text = "LBS"
    weight = package_weight.add_element "Weight"
    weight.text = @weight.to_s
    doc << rss_request
    doc << REXML::XMLDecl.new
    return doc.to_s
  end
end